package com.artollkitplus.benchmark;

import java.io.FileDescriptor;
import java.util.Vector;

import javax.microedition.khronos.opengles.GL10;

import com.artollkitplus.benchmark.R;
import com.artollkitplus.benchmark.DebugFps;

import android.content.res.AssetFileDescriptor;
import android.util.Log;


public class MarkerInfo {

	private int markerNum = -1;
	private boolean initialized = false;
	private int screenWidth = 0;
	private int screenHeight = 0;
	public int imageWidth = 0;
	public int imageHeight = 0;
	///
	public static long timeNativeMarkerDetection = 0;
	private static Vector<Long> nativeMarkerDetectionHistory = new Vector<Long>();
	private static long sumNativeMarkerDetection = 0;
	public static long avgNativeMarkerDetection = 0;
	///
	public static long timeJavaMarkerDetection = 0;
	public static long avgJavaMarkerDetection = 0;
	private static Vector<Long> javaMarkerDetectionHistory = new Vector<Long>();
	private static long sumJavaMarkerDetection = 0;

	private Object transMatMonitor = new Object();
	private DetectMarkerWorker detectMarkerWorker = new DetectMarkerWorker();

	FileDescriptor fd;
	int off;
	int len;
	
	public MarkerInfo(ARActivity arActivity){
		AssetFileDescriptor afd = arActivity.getApplicationContext().getResources().openRawResourceFd(R.raw.camera_calibration);
        if (afd != null)
        {
                fd = afd.getFileDescriptor();
                off = (int) afd.getStartOffset();
                len = (int) afd.getLength();
        }else{
        	Log.e("MarkerInfo", "camera calibration file not found.");
        }
	}
	
	static {
			System.loadLibrary("arplus");
			System.loadLibrary("ar");
	}

	private native void artoolkit_init(int imageWidth, int imageHeight, int screenWidth, int screenHeight, String sdCard);

	private native void artoolkitPlus_init(int imageWidth, int imageHeight,
			int screenWidth, int screenHeight, FileDescriptor fd, long off, long len, long currentARSettings, String sdCard);

	private native long artoolkit_detectmarkers(byte[] in, Object transMatMonitor);

	private native long artoolkitPlus_detectmarkers(byte[] in, Object transMatMonitor);

	private native void artoolkitDraw();
	
	private native void artoolkitPlusDraw();

	private native int grayToRgb(byte src[], int dst[]);

	public void setScreenSize(int width, int height) {
		this.screenWidth = width;
		this.screenHeight = height;
		initialize();
	}

	public void setImageSize(int width, int height) {
		this.imageWidth = width;
		this.imageHeight = height;
		initialize();
	}

	private void initialize() {
		if (screenWidth > 0 && screenHeight > 0 && imageWidth > 0 && imageHeight > 0) {
			artoolkitPlus_init(imageWidth, imageHeight, screenWidth,screenHeight, fd, off, len,CurrentConfig.CURRENT_AR_SETTINGS,IO.sdCardDir);
			artoolkit_init(imageWidth, imageHeight, screenWidth,screenHeight,IO.sdCardDir);
			initialized = true;
		}
	}

	public void detectMarkers(byte[] image) {
		if (initialized) {
			detectMarkerWorker.nextFrame(image);
		}
	}

	public void draw(GL10 gl) {
		if (initialized) {
			if(!CurrentConfig.ONLY_CAMERA_PREVIEW){
				if(CurrentConfig.USE_ARTOOLKITPLUS){
					artoolkitPlusDraw();
				}else{
					artoolkitDraw();
				}
			}	
		}
	}
	
	class DetectMarkerWorker extends Thread {
		private byte[] curFrame;
		public DetectMarkerWorker() {
			setPriority(MAX_PRIORITY);
			start();
		}
		@Override
		public synchronized void run() {
			try {
				wait();
			} catch (InterruptedException e) {
			}
			while (true) {
				if(!CurrentConfig.ONLY_CAMERA_PREVIEW){
					long tick = System.currentTimeMillis();
					if (CurrentConfig.USE_ARTOOLKITPLUS) {
						timeNativeMarkerDetection = artoolkitPlus_detectmarkers(curFrame, transMatMonitor);						
						nativeMarkerDetectionHistory.add(timeNativeMarkerDetection);
						if(nativeMarkerDetectionHistory.size()>20){
							nativeMarkerDetectionHistory.remove(0);
						}
						for(int i = 0;i<nativeMarkerDetectionHistory.size();i++){
							sumNativeMarkerDetection += nativeMarkerDetectionHistory.elementAt(i);
						}
						avgNativeMarkerDetection = sumNativeMarkerDetection/nativeMarkerDetectionHistory.size();
						sumNativeMarkerDetection = 0;
					} else {
						artoolkit_detectmarkers(curFrame, transMatMonitor);
					}
					timeJavaMarkerDetection = System.currentTimeMillis() - tick;
					javaMarkerDetectionHistory.add(timeJavaMarkerDetection);
					if(javaMarkerDetectionHistory.size()>20){
						javaMarkerDetectionHistory.remove(0);
					}
					for(int i = 0;i<javaMarkerDetectionHistory.size();i++){
						sumJavaMarkerDetection += javaMarkerDetectionHistory.elementAt(i);
					}
					avgJavaMarkerDetection = sumJavaMarkerDetection/javaMarkerDetectionHistory.size();
					sumJavaMarkerDetection = 0;
				}		
				DebugFps.updateFPS();
				try {
					wait();
				} catch (InterruptedException e) {
				}
			}
		}

		synchronized void nextFrame(byte[] frame) {
			if (this.getState() == Thread.State.WAITING) {
				curFrame = frame;
				this.notify();
			}
		}
	}

}
